#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
HygonJDK 调优脚本: 线程堆栈与锁竞争分析 (第 1.1, 1.2, 1.3 节)
用法:
  cat jstack.log | python3 analyze_jstack.py
  python3 analyze_jstack.py /path/to/jstack.log
"""

import re
import sys
from collections import defaultdict, Counter

# 正则表达式
RE_THREAD_HEADER = re.compile(r'"(.+)" .*cpu=([\d.]+)ms .*nid=([\w_]+)')
RE_THREAD_STATE = re.compile(r'^\s+java\.lang\.Thread\.State: (\w+)(?:\s+\((\w+)\))?', re.MULTILINE)
RE_DEADLOCK = re.compile(r'Found (one|\d+) Java-level deadlock', re.IGNORECASE)
RE_WAITING_TO_LOCK = re.compile(r'^\s+- waiting to lock <(.+)>')
RE_HELD_BY = re.compile(r'which is held by "(.+)"')
RE_PARKING_TO_WAIT = re.compile(r'parking to wait for\s+<(.+)>')
RE_LOCKED_OWNABLE = re.compile(r'^\s+Locked ownable synchronizers:')
RE_LOCKED_OWNABLE_ENTRY = re.compile(r'^\s+- <(.+)>')

def parse_jstack(log_content):
    """解析jstack日志内容"""
    analysis = {
        "deadlocks": [],
        "threads": [],
        "thread_states": Counter(),
        "blocked_info": [],
        "juc_locks": defaultdict(list),
        "interrupted_threads": [],
        "thread_details": []
    }

    # 检查死锁
    analysis["deadlocks"] = RE_DEADLOCK.findall(log_content)

    # 按线程分割 - 改进的分割逻辑
    lines = log_content.split('\n')
    thread_blocks = []
    current_block = []
    
    for line in lines:
        if line.strip() and not line.startswith('   ') and not line.startswith('\t'):
            # 新线程开始
            if current_block:
                thread_blocks.append('\n'.join(current_block))
                current_block = []
        current_block.append(line)
    
    if current_block:
        thread_blocks.append('\n'.join(current_block))
    
    # 第一遍：收集所有线程信息和JUC锁持有者
    for block in thread_blocks:
        if not block.strip():
            continue

        header_match = RE_THREAD_HEADER.search(block)
        if not header_match:
            continue

        thread_name = header_match.group(1)
        cpu_time_ms = float(header_match.group(2))
        nid = header_match.group(3)
        
        state_match = RE_THREAD_STATE.search(block)
        if state_match:
            state = state_match.group(1)
            # 如果有括号内的状态（如 "TIMED_WAITING (parking)"），则使用完整状态
            if state_match.group(2):
                state = f"{state} ({state_match.group(2)})"
        else:
            state = "UNKNOWN"
        
        # 检测线程中断状态
        is_interrupted = "interrupted" in block.lower() or "interrupt" in block.lower()
        if is_interrupted:
            analysis["interrupted_threads"].append(thread_name)
        
        analysis["thread_states"][state] += 1
        analysis["threads"].append({
            "name": thread_name,
            "cpu_ms": cpu_time_ms,
            "state": state,
            "nid": nid,
            "is_interrupted": is_interrupted
        })
        
        # 收集线程详细信息
        thread_detail = {
            "name": thread_name,
            "state": state,
            "cpu_ms": cpu_time_ms,
            "nid": nid,
            "is_interrupted": is_interrupted,
            "stack_trace": block[:500]  # 保存部分堆栈信息用于分析
        }
        analysis["thread_details"].append(thread_detail)

        # 查找 JUC 锁的持有者
        if RE_LOCKED_OWNABLE.search(block) and "None" not in block:
             locked_juc = RE_LOCKED_OWNABLE_ENTRY.findall(block)
             for lock in locked_juc:
                analysis["juc_locks"][lock].append(thread_name)

    # 第二遍：分析锁等待情况（此时juc_locks已填充）
    for block in thread_blocks:
        if not block.strip():
            continue

        header_match = RE_THREAD_HEADER.search(block)
        if not header_match:
            continue

        thread_name = header_match.group(1)
        
        state_match = RE_THREAD_STATE.search(block)
        if state_match:
            state = state_match.group(1)
            if state_match.group(2):
                state = f"{state} ({state_match.group(2)})"
        else:
            state = "UNKNOWN"

        # 分析 synchronized 锁
        if state == "BLOCKED":
            lock_match = RE_WAITING_TO_LOCK.search(block)
            if lock_match:
                lock_id = lock_match.group(1)
                holder_match = RE_HELD_BY.search(block)
                holder = holder_match.group(1) if holder_match else "未知持有者"
                analysis["blocked_info"].append({"waiter": thread_name, "lock": lock_id, "holder": holder})

        # 分析 JUC 锁 (ReentrantLock 等)
        if "WAITING (parking)" in block or "TIMED_WAITING (parking)" in block:
            juc_lock_match = RE_PARKING_TO_WAIT.search(block)
            if juc_lock_match:
                lock_id = juc_lock_match.group(1)
                # 尝试从 Locked ownable synchronizers 查找持有者
                holder = "未知 (JUC 锁)"
                if lock_id in analysis["juc_locks"]:
                    holder = f"推测为: {', '.join(analysis['juc_locks'][lock_id])}"
                
                # 识别具体的JUC锁类型和详细信息
                lock_type = "未知JUC锁"
                lock_details = ""
                
                # 特殊处理常见JUC锁类型
                if "ReentrantLock" in block:
                    lock_type = "ReentrantLock"
                    if "NonfairSync" in block:
                        lock_details = "非公平锁"
                    elif "FairSync" in block:
                        lock_details = "公平锁"
                elif "ForkJoinPool" in block:
                    lock_type = "ForkJoinPool"
                    lock_details = "工作窃取线程池 (等待工作队列)"
                elif "CountDownLatch" in block:
                    lock_type = "CountDownLatch"
                    lock_details = "等待计数器归零"
                elif "ConditionObject" in block:
                    lock_type = "Condition"
                    lock_details = "等待条件信号"
                elif "ThreadPoolExecutor" in block:
                    lock_type = "ThreadPoolExecutor"
                    lock_details = "等待任务执行"
                elif "ArrayBlockingQueue" in block:
                    lock_type = "ArrayBlockingQueue"
                    lock_details = "有界阻塞队列操作"
                elif "LinkedBlockingQueue" in block:
                    lock_type = "LinkedBlockingQueue"
                    lock_details = "可选有界阻塞队列操作"
                elif "SynchronousQueue" in block:
                    lock_type = "SynchronousQueue"
                    lock_details = "无缓冲阻塞队列操作"
                elif "Semaphore" in block:
                    lock_type = "Semaphore"
                    lock_details = "等待获取信号量许可"
                elif "CyclicBarrier" in block:
                    lock_type = "CyclicBarrier"
                    lock_details = "等待屏障点"
                elif "Phaser" in block:
                    lock_type = "Phaser"
                    lock_details = "等待阶段同步"
                elif "ReadWriteLock" in block:
                    lock_type = "ReadWriteLock"
                    if "ReadLock" in block:
                        lock_details = "读锁"
                    elif "WriteLock" in block:
                        lock_details = "写锁"
                elif "StampedLock" in block:
                    lock_type = "StampedLock"
                    lock_details = "乐观读/悲观写锁"
                elif "MapReduceTask" in block:
                    lock_type = "MapReduceTask"
                    lock_details = "等待任务完成"
                elif "FutureTask" in block:
                    lock_type = "FutureTask"
                    lock_details = "等待异步任务结果"
                elif "CompletableFuture" in block:
                    lock_type = "CompletableFuture"
                    lock_details = "等待异步计算完成"
                
                # 如果锁类型已知但持有者未知，更新持有者信息
                if lock_type != "未知JUC锁" and holder == "未知 (JUC 锁)":
                    holder = f"{lock_type} ({lock_details})"
                    
                analysis["blocked_info"].append({
                    "waiter": thread_name,
                    "lock": lock_id,
                    "holder": holder,
                    "lock_type": lock_type,
                    "lock_details": lock_details,
                    "is_juc": True
                })


    return analysis

def print_jstack_report(analysis):
    """打印分析报告"""
    
    print("=" * 70)
    print("HygonJDK 调优助手 - 线程堆栈分析报告")
    print("=" * 70)

    # 1. 死锁分析 (Section 1.1)
    print("\n--- 1. 死锁分析 ---")
    if analysis["deadlocks"]:
        print(f"[\033[91m严重\033[0m] 检测到 {len(analysis['deadlocks'])} 个Java级别死锁！请立即在日志中搜索 'Found ... deadlock'。")
    else:
        print("[\033[92m正常\033[0m] 未检测到Java级别死锁。")

    # 2. 线程状态概览 (Section 1.3)
    print("\n--- 2. 线程状态概览 ---")
    total_threads = len(analysis['threads'])
    print(f"总线程数: {total_threads}")
    
    # 线程状态详细解释
    state_explanations = {
        "RUNNABLE": "正在运行或等待CPU分配资源（包含操作系统的ready和running状态）",
        "BLOCKED": "等待获取监视器锁（synchronized），处于阻塞状态",
        "WAITING": "无限期等待其他线程唤醒（Object.wait()、Thread.join()、LockSupport.park()）",
        "TIMED_WAITING": "有限时间等待（Thread.sleep()、Object.wait(timeout)、Thread.join(timeout)）",
        "NEW": "线程已创建但未启动",
        "TERMINATED": "线程已执行完毕"
    }
    
    for state, count in analysis["thread_states"].items():
        color = "\033[0m"
        if state == "BLOCKED":
            color = "\033[91m"  # 红色 - 阻塞状态需要关注
        elif state == "RUNNABLE":
            color = "\033[92m"  # 绿色 - 正常运行状态
        elif "WAITING" in state:
            color = "\033[93m"  # 黄色 - 等待状态需要监控
        
        percentage = (count/total_threads*100)
        print(f"  - {state:<20}: {color}{count}\033[0m ({percentage:.1f}%)")
        
        # 显示状态解释和性能提示
        if state in state_explanations:
            explanation = state_explanations[state]
            if state == "BLOCKED" and percentage > 5:
                print(f"    ⚠️  {explanation} - 阻塞线程比例较高，可能存在锁竞争问题")
            elif state == "WAITING" and percentage > 10:
                print(f"    ⚠️  {explanation} - 等待线程比例较高，检查线程协作")
            elif state == "TIMED_WAITING" and percentage > 20:
                print(f"    ⚠️  {explanation} - 超时等待线程比例较高，可能存在性能问题")
            else:
                print(f"    📝 {explanation}")

    # 3. CPU消耗排行 (Top 5)
    print("\n--- 3. CPU 消耗排行 (Top 5) ---")
    sorted_by_cpu = sorted(analysis["threads"], key=lambda x: x["cpu_ms"], reverse=True)
    for i, thread in enumerate(sorted_by_cpu[:5]):
        cpu_info = f"{thread['cpu_ms']:.2f} ms"
        if thread['cpu_ms'] > 1000:
            cpu_info = f"\033[91m{cpu_info}\033[0m"  # 红色高亮高CPU消耗
        elif thread['cpu_ms'] > 100:
            cpu_info = f"\033[93m{cpu_info}\033[0m"  # 黄色高亮中等CPU消耗
        
        state_info = thread['state']
        if thread.get('is_interrupted', False):
            state_info = f"{state_info} \033[91m[中断]\033[0m"
        
        print(f"  {i+1}. \"{thread['name']}\" - {cpu_info} (状态: {state_info})")
    
    # 4. 线程中断状态分析
    print("\n--- 4. 线程中断状态分析 ---")
    if analysis["interrupted_threads"]:
        print(f"[\033[93m注意\033[0m] 检测到 {len(analysis['interrupted_threads'])} 个线程处于中断状态:")
        for thread_name in analysis["interrupted_threads"][:5]:  # 最多显示5个
            print(f"  - {thread_name}")
        print("  📝 线程中断是一种协作机制，需要检查线程是否正确处理中断请求")
    else:
        print("[\033[92m正常\033[0m] 未检测到线程中断状态")

    # 5. 锁竞争分析 (Section 1.2)
    print("\n--- 5. 锁竞争分析 (synchronized & JUC) ---")
    if not analysis["blocked_info"]:
        print("[\033[92m正常\033[0m] 未检测到明显的锁等待 (BLOCKED 或 parking)。")
        return

    # 尝试关联 JUC 锁持有者
    for item in analysis["blocked_info"]:
        if item["holder"] == "未知 (JUC 锁)" and item["lock"] in analysis["juc_locks"]:
            item["holder"] = f"推测为: {', '.join(analysis['juc_locks'][item['lock']])}"

    # 按锁聚合
    contention = defaultdict(list)
    lock_info = {}
    for item in analysis["blocked_info"]:
        contention[item["lock"]].append(item["waiter"])
        # 保存锁的详细信息
        if item["lock"] not in lock_info:
            lock_info[item["lock"]] = {
                "holder": item["holder"],
                "lock_type": item.get("lock_type", "synchronized"),
                "lock_details": item.get("lock_details", ""),
                "is_juc": item.get("is_juc", False)
            }

    # 统计锁类型分布
    lock_type_stats = defaultdict(int)
    for item in analysis["blocked_info"]:
        lock_type = item.get("lock_type", "synchronized")
        lock_type_stats[lock_type] += 1

    print(f"[\033[93m注意\033[0m] 共检测到 {len(analysis['blocked_info'])} 个线程处于锁等待状态。")
    print("锁类型分布:")
    for lock_type, count in sorted(lock_type_stats.items(), key=lambda x: x[1], reverse=True):
        print(f"  - {lock_type}: {count} 个等待")
    
    print("\n按锁聚合 (Top 5 竞争最激烈的锁):")
    
    sorted_contention = sorted(contention.items(), key=lambda x: len(x[1]), reverse=True)
    
    for i, (lock_id, waiters) in enumerate(sorted_contention[:5]):
        waiter_count = len(waiters)
        info = lock_info[lock_id]
        
        # 确定锁类型显示颜色
        lock_type_color = "\033[96m"  # 默认蓝色
        if info["is_juc"]:
            if info["lock_type"] in ["ReentrantLock", "ReadWriteLock", "StampedLock"]:
                lock_type_color = "\033[95m"  # 紫色显示显式锁
            else:
                lock_type_color = "\033[94m"  # 亮蓝色显示其他JUC锁
        
        print(f"\n  {i+1}. 锁: \033[96m{lock_id}\033[0m")
        print(f"     类型: {lock_type_color}{info['lock_type']}\033[0m", end="")
        if info["lock_details"]:
            print(f" ({info['lock_details']})")
        else:
            print()
        print(f"     持有者: \033[91m{info['holder']}\033[0m")
        print(f"     等待线程数: \033[91m{waiter_count}\033[0m")
        print(f"     等待者: {', '.join(waiters[:3])}{'...' if waiter_count > 3 else ''}")

    # 6. 线程状态转换分析与优化建议
    print("\n--- 6. 线程状态转换分析与优化建议 ---")
    
    # 分析线程状态转换模式
    blocked_count = analysis["thread_states"].get("BLOCKED", 0)
    waiting_count = analysis["thread_states"].get("WAITING", 0) + analysis["thread_states"].get("TIMED_WAITING", 0)
    runnable_count = analysis["thread_states"].get("RUNNABLE", 0)
    
    print("📊 线程状态转换分析:")
    print(f"  - BLOCKED -> RUNNABLE: {blocked_count} 个线程等待锁释放")
    print(f"  - WAITING -> RUNNABLE: {waiting_count} 个线程等待唤醒")
    print(f"  - RUNNABLE 线程数: {runnable_count}")
    
    # 提供优化建议
    print("\n🎯 性能优化建议:")
    
    if blocked_count > 0:
        print("  🔴 锁竞争优化:")
        print("    - 减少同步块范围，使用更细粒度的锁")
        print("    - 考虑使用读写锁(ReadWriteLock)替代互斥锁")
        print("    - 使用并发集合类替代同步集合")
    
    if waiting_count > runnable_count * 0.5:  # 等待线程超过运行线程的一半
        print("  🟡 线程协作优化:")
        print("    - 检查 Object.wait()/notify() 使用是否正确")
        print("    - 避免不必要的 Thread.sleep() 调用")
        print("    - 使用线程池管理线程生命周期")
    
    if runnable_count < total_threads * 0.1:  # 运行线程少于总线程的10%
        print("  🟡 CPU资源利用优化:")
        print("    - 检查是否存在CPU密集型任务阻塞")
        print("    - 考虑使用异步编程减少线程等待")
        print("    - 优化I/O操作，使用NIO或异步I/O")
    
    if analysis["interrupted_threads"]:
        print("  🟡 线程中断处理:")
        print("    - 确保线程正确检查中断状态")
        print("    - 在长时间操作中定期调用 Thread.interrupted()")
        print("    - 合理使用 InterruptedException 处理")
    
    if not any([blocked_count > 0, waiting_count > runnable_count * 0.5, runnable_count < total_threads * 0.1]):
        print("  ✅ 当前线程状态分布良好，继续保持当前配置")

    print("=" * 70)

def main():
    try:
        if len(sys.argv) > 1:
            # 从文件读取
            filepath = sys.argv[1]
            with open(filepath, 'r', encoding='utf-8') as f:
                log_content = f.read()
        else:
            # 从 stdin 读取
            log_content = sys.stdin.read()
            
        if not log_content:
            print("错误: 未提供日志内容。", file=sys.stderr)
            print(__doc__, file=sys.stderr)
            sys.exit(1)

        analysis = parse_jstack(log_content)
        print_jstack_report(analysis)

    except FileNotFoundError:
        print(f"错误: 文件未找到 {sys.argv[1]}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"发生错误: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
